package com.vcc.web.core.configurer;

import cn.dev33.satoken.interceptor.SaInterceptor;
import com.alibaba.fastjson2.JSONWriter;
import com.alibaba.fastjson2.filter.ValueFilter;
import com.alibaba.fastjson2.support.config.FastJsonConfig;
import com.alibaba.fastjson2.support.spring.http.converter.FastJsonHttpMessageConverter;
import com.vcc.web.core.config.AccountConfig;
import com.vcc.web.core.config.PingPongConfig;
import com.vcc.web.core.interceptor.AuthInterceptor;
import com.vcc.web.core.resolver.CurrentClientIpMethodArgumentResolver;
import com.vcc.web.core.resolver.CurrentROStatusMethodArgumentResolver;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.*;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

@Configuration
public class WebConfigurer implements WebMvcConfigurer {

    private static final Logger logger = LoggerFactory.getLogger(WebConfigurer.class);

    @Autowired
    private AuthInterceptor authInterceptor;

    @Autowired
    private AccountConfig accountConfig;

    @Value("classpath:/redisson-dev.yml")
    private Resource devConfigFile;

    @Value("classpath:/redisson-prod.yml")
    private Resource prodConfigFile;

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        // 1. 配置fastjson
        // 1. 配置fastjson
        com.alibaba.fastjson2.support.config.FastJsonConfig config = new FastJsonConfig();

        config.setDateFormat("yyyy-MM-dd HH:mm:ss");
        config.setCharset(StandardCharsets.UTF_8);
        config.setWriterFeatures(
                JSONWriter.Feature.WriteNullListAsEmpty,  //json格式化
                JSONWriter.Feature.PrettyFormat,  //输出map中value为null的数据
                JSONWriter.Feature.WriteMapNullValue,  //输出boolean 为 false
                JSONWriter.Feature.WriteNullBooleanAsFalse,  //输出list 为 []
                JSONWriter.Feature.WriteNullListAsEmpty,  //输出number 为 0
//                JSONWriter.Feature.WriteNullNumberAsZero,  //输出字符串 为 ""
                JSONWriter.Feature.WriteNullStringAsEmpty,  //对map进行排序
                JSONWriter.Feature.MapSortField
        );
        config.setWriterFilters();

        config.setWriterFilters((ValueFilter) (source, name, value) -> {
            if (value instanceof Long && name.contains("id")) {
                return value.toString();
            }
            if (value instanceof Long && name.contains("Id")) {
                return value.toString();
            }
            if (value instanceof Long && value.toString().length() >= 16) {
                return value.toString();
            } else {
                return value;
            }
        });

        com.alibaba.fastjson2.support.spring.http.converter.FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();

        // 处理中文乱码问题


//        //处理字符串, 避免直接返回字符串的时候被添加了引号
//        val serializeConfig: SerializeConfig = SerializeConfig.globalInstance
//        serializeConfig.put(Long::class.java, com.alibaba.fastjson2.serializer.ToStringSerializer.instance)
//        serializeConfig.put(java.lang.Long.TYPE, com.alibaba.fastjson2.serializer.ToStringSerializer.instance)
//        config.setSerializeConfig(serializeConfig)

        // 2. 添加fastjson转换器

        // 2. 添加fastjson转换器
        List<MediaType> supportedMediaTypes = new ArrayList();

        // 3. 添加支持的媒体类型

        // 3. 添加支持的媒体类型
        supportedMediaTypes.add(MediaType.APPLICATION_JSON);
        supportedMediaTypes.add(MediaType.APPLICATION_ATOM_XML);
        supportedMediaTypes.add(MediaType.APPLICATION_FORM_URLENCODED);
        supportedMediaTypes.add(MediaType.APPLICATION_OCTET_STREAM);
        supportedMediaTypes.add(MediaType.APPLICATION_PDF);
        supportedMediaTypes.add(MediaType.APPLICATION_RSS_XML);
        supportedMediaTypes.add(MediaType.APPLICATION_XHTML_XML);
        supportedMediaTypes.add(MediaType.APPLICATION_XML);
        supportedMediaTypes.add(MediaType.IMAGE_GIF);
        supportedMediaTypes.add(MediaType.IMAGE_JPEG);
        supportedMediaTypes.add(MediaType.IMAGE_PNG);
        supportedMediaTypes.add(MediaType.TEXT_EVENT_STREAM);
        supportedMediaTypes.add(MediaType.TEXT_HTML);
        supportedMediaTypes.add(MediaType.TEXT_MARKDOWN);
        supportedMediaTypes.add(MediaType.TEXT_PLAIN);
        supportedMediaTypes.add(MediaType.TEXT_XML);

        converter.setSupportedMediaTypes(supportedMediaTypes);

        //4 将convert添加到converters
        //4 将convert添加到converters
        converter.setFastJsonConfig(config);
        converters.add(0, converter);
    }


    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        configurer.defaultContentType(MediaType.APPLICATION_JSON, MediaType.TEXT_XML, MediaType.APPLICATION_XML);
    }

//    @Bean
//    public RedisTemplate<Object, Object> redisTemplate() {
//        RedisConnectionFactory redisConnectionFactory = new RedisConnectionFactory();
//        // 1.创建 redisTemplate 模版
//        RedisTemplate<Object, Object> template = new RedisTemplate<Object, Object>();
//        // 2.关联 redisConnectionFactory
//        template.setConnectionFactory(redisConnectionFactory);
//        // 3.创建 序列化类
//        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
//        ObjectMapper om = new ObjectMapper();
//        // 4.设置可见度
//        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
//        // 5.启动默认的类型
//        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
//        // 6.序列化类，对象映射设置
//        jackson2JsonRedisSerializer.setObjectMapper(om);
//        // 7.设置 value 的转化格式和 key 的转化格式
//        template.setValueSerializer(jackson2JsonRedisSerializer);
//        template.setKeySerializer(new StringRedisSerializer());
//        template.afterPropertiesSet();
//        return template;
//    }

    /**
     * 拦截器
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 多个拦截器组成一个拦截器链
        // addPathPatterns 用于添加拦截规则
        // excludePathPatterns 用户排除拦截
        registry.addInterceptor(new SaInterceptor()).addPathPatterns("/**");
        registry.addInterceptor(authInterceptor)
                .addPathPatterns("/**");
//                .excludePathPatterns(
//                Arrays.asList("/",
//                        "/swagger-ui.html",
//                        "/swagger-ui/",
//                        "/*.html",
//                        "/favicon.ico",
//                        "/**/*.html",
//                        "/**/*.css",
//                        "/**/*.js",
//                        "/swagger-resources/**",
//                        "/v3/api-docs/**")
//        );
    }


    @Override
    public void addCorsMappings(CorsRegistry registry) {
        //设置允许跨域的路径
        registry.addMapping("/**")
                //设置允许跨域请求的域名
                .allowedOriginPatterns("*")
                //是否允许证书 不再默认开启
                .allowCredentials(true)
                //设置允许的方法
                .allowedMethods("*")
                //跨域允许时间
                .maxAge(3600);
    }
//
//    private CorsConfiguration buildConfig() {
//        CorsConfiguration corsConfiguration = new CorsConfiguration();
//        corsConfiguration.addAllowedOrigin("*");
//        corsConfiguration.addAllowedHeader("*");
//        corsConfiguration.addAllowedMethod("*");
//        corsConfiguration.setAllowCredentials(true);//这两句不加不能跨域上传文件，
//        corsConfiguration.setMaxAge(3600L);//加上去就可以了
//        return corsConfiguration;
//    }
//
//    /**
//     * 跨域过滤器
//     * @return
//     */
//    @Bean
//    public CorsFilter corsFilter() {
//        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
//        source.registerCorsConfiguration("/**", buildConfig()); // 4
//        return new CorsFilter(source);
//    }


    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        argumentResolvers.add(currentClientIpMethodArgumentResolver());
        argumentResolvers.add(currentROStatusMethodArgumentResolver());
    }

    @Bean
    public CurrentClientIpMethodArgumentResolver currentClientIpMethodArgumentResolver() {
        return new CurrentClientIpMethodArgumentResolver();
    }

    @Bean
    public CurrentROStatusMethodArgumentResolver currentROStatusMethodArgumentResolver() {
        return new CurrentROStatusMethodArgumentResolver();
    }


    @Bean
    public RedissonClient redissonClient()  {
        try{
            Config config;
            if ("dev".equals(accountConfig.getActive())) {
                config = Config.fromYAML(devConfigFile.getInputStream());
            } else {
                config = Config.fromYAML(prodConfigFile.getInputStream());
            }
            return Redisson.create(config);
        }catch (Exception e){
            logger.error("初始化失败",e);
            return null;
        }
    }

    @Bean
    public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
        ThreadPoolTaskScheduler executor = new ThreadPoolTaskScheduler();
        executor.setPoolSize(10);
        executor.setThreadNamePrefix("threadPoolTaskScheduler-");
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setAwaitTerminationSeconds(60);
        return executor;
    }
}
